import mpPanelImg from '@/assets/image/screenshot/mp-panel.png';
import mpDataHarborImg from '@/assets/image/screenshot/mp-data-harbor.png';
import PlatformTag from '@/components/Docs/components/PlatformTag'
import { Link } from 'react-router-dom'

# PageSpy API

## constructor(config)#constructor

创建一个 PageSpy 实例。

- 类型

  ```ts
  declare class PageSpy {
    constructor(config: InitConfig)
  }
  ```

- 详细信息

  构造函数接受一个 `config` 对象作为初始化参数。

### config.api

服务端地址。

- 类型：`string`

- **<PlatformTag type="browser" />**

  SDK 会从引入的路径自动分析并决定 Server 的地址`api`和调试端的地址`clientOrigin`。假设你通过 `<script src="https://example.com/page-spy/index.min.js">` 引入 SDK，那么 SDK 会在内部设置：
  - api: `"example.com"`
  - clientOrigin: `"https://example.com"`

  如果你的服务部署在别处，就需要在这里手动指定去覆盖。

- **<PlatformTag type="mp" /> <PlatformTag type="rn" /> <PlatformTag type="harmony" />**

  该字段为必填。

### config.clientOrigin <PlatformTag type="browser" />

- 类型：`string`

### config.lang

指定 SDK 显示的语言。

- 类型：`"zh" | "en"`
- 默认值：`null`

  如果未手动指定，SDK 会按照下面的策略自动选择：

  1. 读取 html 的 `lang` 属性，如果是 `['zh-CN', 'zh-HK', 'zh-TW', 'zh', 'zh-Hans-CN']` 之一，则显示中文，否则使用英文；
  2. 读取 `navigator.language` 属性，如果是 `['zh-CN', 'zh-HK', 'zh-TW', 'zh', 'zh-Hans-CN']` 之一，则显示中文，否则使用英文；
  
### config.project

作为信息的一种聚合，可以在调试端房间列表进行搜索
  
- 类型：`string`
- 默认值：`default`

    
    
### config.title

用户自定义参数，可以用于区分当前调试的客户端。

对应的信息显示在每个调试连接面板的「设备id」下方。

- 类型：`string`
- 默认值：`--`

    
### config.enableSSL

手动指定 PageSpy 服务的 scheme。

- 类型：`boolean`

- 详细信息

  传递 boolean 值：
    - true：SDK 将通过 ["https://", "wss://"] 访问 PageSpy 服务
    - false：SDK 将通过 ["http://", "ws://"] 访问 PageSpy 服务

- <PlatformTag type="browser" />

  不设置该值，SDK 会根据页面所在的地址自动分析。

  在 SDK 无法正确分析出 scheme 时，例如 PageSpy 的浏览器插件是通过 chrome-extension://xxx/sdk/index.min.js 引入 SDK，这会被 SDK 解析成无效的 "chrome-extension://" 并回退到["http://", "ws://"]。此时可以手动设定该字段。

- <PlatformTag type="mp" /> <PlatformTag type="rn" /> <PlatformTag type="harmony" />

  这些环境一般强制要求 https，因此默认为 `true`。如果需支持 http（一般是在开发环境中），可以设置为 false。


  
### config.disabledPlugins

PageSpy 内置的插件都是开箱即用的，你可以手动指定禁用哪些插件。

- 类型：`string[]`


### config.serializeData

是否允许 SDK 在收集离线日志时，序列化非基本类型的数据，序列化的目的是方便在回放时查看。

- 类型：`boolean`
- 默认值：`false`


### config.useSecret

是否启用权限认证功能。

- 类型：`boolean`
- 默认值：`false`
- 详细信息：

  启用后，SDK会生成 6 位数的随机 “密钥”；调试端进入房间时要求输入对应的密钥。
  
### config.messageCapacity

缓存数据的最大数量。

- 类型：`number`
- 默认值：`1000`
- 详细信息：

  SDK 在调试端进入房间之前会在内存中缓存数据，以便于调试端进入房间后可以看到之前的数据。

  但数据体积会越来越大，因此可以指定 SDK 在本地最多缓存多少条数据记录。


### config.dataProcessor

数据处理，用户可以通过该属性自定义修改、忽略数据。

- 类型：
  ```ts
  declare interface DataProcessor {
    console?: (data: ConsoleData) => boolean;
    network?: (data: RequestItem) => boolean;
    storage?: (data: StorageData) => boolean;
    database?: (data: DatabaseData) => boolean;
    page?: (data: PageData) => boolean;
    system?: (data: SystemData) => boolean;
  }
  ```

- 详细信息

  处理函数分别对应各个内置的插件，用户可以在函数中直接修改数据，函数执行完成后 PageSpy 处理修改后的数据。如果函数返回 false，PageSpy 会 忽略掉该条数据：这意味着在两种模式下的调试端都不会看到这条数据。

  查看详情：<Link to="/docs/changelog#v1-9-2">v1.9.2</Link>


### config.disabledOnProd <PlatformTag type="mp" />

在小程序的生产环境禁用 PageSpy。

- 类型：`boolean`
- 默认值：`true`
- 详细信息：

  PageSpy 作为一款调试工具，主要应用于开发测试环节，不建议在生产环境使用，且小程序平台一般对性能更为敏感，因此该字段默认为 true。


### config.offline <PlatformTag type="browser" />

离线模式。

- 类型：`boolean`

- 默认值：`false`

- 详细信息：

  在 PageSpy@1.7.4 支持离线回放功能后，客户端集成的 SDK 可以不用和调试端建立连接，通过 DataHarborPlugin 收集数据、导出离线日志，成为新的使用方式。
  默认值 false。用户设置为 Truthy 值，会进入 "离线模式"，具体表现为 PageSpy 不会创建房间、建立 WebSocket 连接。

  目前仅适用浏览器环境的 SDK。


### config.autoRender <PlatformTag type="browser" />

指示 SDK 初始化完成，是否自动在客户端左下角渲染「圆形白底带 Logo」的控件。

- 类型：`boolean`

- 默认值：`true`

- 详细信息：

  如果设置为 false, 可以调用 `window.$pageSpy.render()` 手动渲染。


### config.logo <PlatformTag type="browser" />

自定义控件渲染的 logo

- 类型：`string`

### config.primaryColor <PlatformTag type="browser" />

设置主题色，用于 modal 和 toast 中。

- 类型：`string`

### config.modal <PlatformTag type="browser" />

设置 modal 里的 logo 和 title。

- 类型：

  ```ts
  declare interface ModalConfig {
    logo?: string;
    title?: string;
  }
  ```
- 默认值：

  ```ts
  {
    logo: "",
    title: "PageSpy"
  }
  ```

### config.gesture <PlatformTag type="browser" />

通过手势操作或键盘方向键启用 PageSpy。

- 类型：`Command | null`。

  手势识别依赖于 [iseedeadpeople](https://github.com/YanagiEiichi/iseedeadpeople)，其 Command 定义如下：

  ```ts
  declare const DIRECTION_CHARACTERS: readonly ["U", "R", "D", "L"];
  type Direction = (typeof DIRECTION_CHARACTERS)[number];

  type Command = readonly Direction[];
  ```
  
- 默认值：`null`，禁用手势。

- 示例

  ```ts
  new PageSpy({
    ...,
    // 仅当用户完成 "上上下下左右左右" 的输入时，PageSpy 才会启用，具体操作如下：
    // - 移动设备上：在屏幕上「滑动」
    // - 桌面设备上：在键盘上按下「方向键」
    gesture: ['U', 'U', 'D', 'D', 'L', 'R', 'L', 'R'],
  })
  ```


## registerPlugin()#registerPlugin

静态方法，注册一个插件。

- 类型

  ```ts
  declare class PageSpy {
    static registerPlugin(plugin: PageSpyPlugin): void;
  }
  ```

- 详细信息

  在实例化 PageSpy 之前调用，参数是实现了 `PageSpyPlugin` 的插件实例，每个插件实例都应带有 `name` 属性。同样名称的插件如果重复注册，插件实例只会被注册一次，同时控制台会打印警告信息。

- 示例

  ```ts
  class DataHarborPlugin implements PageSpyPlugin {
    name = 'DataHarborPlugin'

    ... // 插件的实现
  }

  PageSpy.registerPlugin(new DataHarborPlugin());
  
  // 重复调用，插件只会被注册一次
  // PageSpy.registerPlugin(new DataHarborPlugin());
  ```

## pluginsWithOrder

按插件的 `enforce` 属性排序的已注册插件列表。

- 类型

  ```ts
  declare class PageSpy {
    static plugins: Record<PluginOrder | 'normal', PageSpyPlugin[]>;
    static get pluginsWithOrder(): PageSpyPlugin[];
  }
  ```

- 详细信息

  每个插件都应提供 `enforce: PluginOrder` 属性，如果未提供则默认为 `enforce: "normal"`，之后 PageSpy 会按照 `pre - normal - post` 的顺序维护插件列表。


## updateRoomInfo()#updateRoomInfo

实例化之后，更新连接信息。

- 类型

  ```ts
  type UpdateConfig = {
      title?: string;
      project?: string;
  };

  declare class PageSpy {
    updateRoomInfo(obj: UpdateConfig): void;
  }
  ```

- 详细信息

  客户端的标识信息在 PageSpy 初始化的时候如果还不知道，之后可以通过这个方法更新。

- 示例

  ```ts
  window.$pageSpy = new PageSpy({
    title: '--',
    project: '--'
  })

  async function YourCode() {
    // 业务逻辑异步加载客户端标识，比如：当前用户、当前项目
    const { title, project } = await xxx();

    window.$pageSpy.updateRoomInfo({
      title,
      project
    })
  }
  ```

## abort()#abort

销毁当前实例。

- 类型

  ```ts
  declare class PageSpy {
    abort(): void;
  }
  ```

- 详细信息

  PageSpy 会断开连接、从文档中移除相关 DOM、清空已缓存的数据、调用所有已注册插件的 `onReset()` 方法。
  
  当前上下文中被代理或者被重写的 API，如浏览器中的 `window.fetch`，都会恢复到实例化 PageSpy 之前的状态。

- 示例

  ```ts
  window.$pageSpy = new PageSpy(...);

  window.$pageSpy.abort();
  ```

## version

当前使用的 PageSpy 版本。

- 类型

  ```ts
  declare class PageSpy {
    version: string;
  }
  ```

- 示例

  ```ts
  window.$pageSpy = new PageSpy(...);

  console.log(window.$pageSpy.version);
  ```

## config

配置信息。配置因平台不同存在差异，比如小程序端特有的 `config.disableOnProd`。

- 类型

  ```ts
  declare class PageSpy {
    config: Config;
  }
  ```

## socketStore

封装了 WebSocket 实例，提供注册消息事件、收到指定消息后触发回调，广播消息。

- 类型

  ```ts
  interface SocketStoreType {
    addListener(type: InteractiveType, fn: InteractiveEventCallback): void;
    addListener(type: InternalType, fn: InternalEventCallback): void;

    removeListener(type: InteractiveType, fn: InteractiveEventCallback): void;
    removeListener(type: InternalType, fn: InternalEventCallback): void;

    dispatchEvent(type: InteractiveType | InternalType, data: InteractiveEvent): void;
    dispatchEvent(type: InternalType, data: any): void;

    broadcastMessage(message: MessageItem, noCache?: boolean): void;
  }
  ```

- 详细信息

  `addListener() / removeListener() / dispatchEvent()` 的第一个参数是消息类型，我们把消息类型分为 **“交互式的”** 和 **“内部的”** 两种：
  
  - **“交互式的”** 消息类型用于和调试端交互，例如：调试端上线、发送代码到客户端执行、点击展开对象详情，这些都会作为消息事件发送到 SDK，SDK 按需做出响应；
  - **“内部的”** 消息类型当前用于插件之间交互，例如各个插件产生数据后会通过 `socketStore.dispatchEvent('public-data')` 派发事件，同为插件的 `DataHarborPlugin` 监听了这个事件后可以对数据另作处理。

  `broadcastMessage()` 广播消息。第一个参数是来自各个插件发给调试端的数据，第二个参数 `noCache` 用于插件告知 `socketStore` 当前发送的这条消息是否应该被缓存。把数据缓存下来的目的是当调试端 “上线” 后可以看到历史的消息，但并不是所有的数据都需要缓存，例如：客户端发起网络请求，无论成功或失败，只需要缓存最终态的。

- 示例

  ```ts
  // ConsolePlugin 的具体实现请前往仓库查看
  class ConsolePlugin implements PageSpyPlugin {
    onInit({ socketStore }) {
      socketStore.addListener('debug', ({ source }, reply) => {
        ...
      })

      socketStore.broadcastMessage(...)
    }
  }
  ```

## showPanel() <PlatformTag type="mp" />

在小程序环境中弹出调试面板。

- 类型
  ```ts
  declare class PageSpy {
    showPanel(): void;
  }
  ```
  
- 详细信息

  <img src={mpPanelImg} style={{width: 375}} />

  该面板支持插件注册自定义按钮，例如如果注册了 [DataHarborPlugin](./offline-log#mp)，该面板中会出现一个「上传离线日志」按钮：

  <img src={mpDataHarborImg} style={{maxWidth: 375}} />


